//
//  YuanXinWebViewManager.m
//  YuanXinWebView
//
//  Created by 晏德智 on 16/7/27.
//  Copyright © 2016年 晏德智. All rights reserved.
//

#import "YuanXinWebViewManager.h"
#import "YuanXinWebView.h"
#import "YuanXinWKWebView.h"
#import <WebKit/WebKit.h>
#import "JWCacheURLProtocol.h"

@interface YuanXinWebViewManager () <YuanXinWebViewDelegate>

@end

@implementation YuanXinWebViewManager
{
    NSConditionLock *_shouldStartLoadLock;
    BOOL _shouldStartLoad;
}

RCT_EXPORT_MODULE()

- (UIView *)view
{
    YuanXinWebView *webView = [[YuanXinWKWebView alloc] init];
    webView.delegate = self;
    return webView;
}

RCT_EXPORT_VIEW_PROPERTY(source, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(progressStyle, NSDictionary)
RCT_EXPORT_VIEW_PROPERTY(showProgress, BOOL)
RCT_REMAP_VIEW_PROPERTY(bounces, _webView.scrollView.bounces, BOOL)
RCT_REMAP_VIEW_PROPERTY(scrollEnabled, _webView.scrollView.scrollEnabled, BOOL)
RCT_EXPORT_VIEW_PROPERTY(injectedJavaScript, NSString)
RCT_EXPORT_VIEW_PROPERTY(userName, NSString)
RCT_EXPORT_VIEW_PROPERTY(password, NSString)
RCT_EXPORT_VIEW_PROPERTY(contentInset, UIEdgeInsets)
RCT_EXPORT_VIEW_PROPERTY(automaticallyAdjustContentInsets, BOOL)
RCT_EXPORT_VIEW_PROPERTY(sendCookies, BOOL)
RCT_EXPORT_VIEW_PROPERTY(assetsCacheEnable, BOOL)
RCT_REMAP_VIEW_PROPERTY(longPressForbidden, noTouchCallout, BOOL)
RCT_EXPORT_VIEW_PROPERTY(iosKeyboardDisableAutoScroll, BOOL)
RCT_EXPORT_VIEW_PROPERTY(useURLProtocolForWKWebview, BOOL)
RCT_EXPORT_VIEW_PROPERTY(onLoadingStart, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingFinish, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onLoadingError, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onShouldStartLoadWithRequest, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onProgress, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(onBridgeMessage, RCTDirectEventBlock)
RCT_EXPORT_VIEW_PROPERTY(userAgent, NSString)

RCT_EXPORT_METHOD(goBack:(nonnull NSNumber *)reactTag)
{
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view = viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWKWebView, got: %@", view);
        } else {
            YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView goBack];
        }
    }];
}

RCT_EXPORT_METHOD(goForward:(nonnull NSNumber *)reactTag)
{
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view =  viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWKWebView, got: %@", view);
        } else {
            YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView goForward];
        }
    }];
}

RCT_EXPORT_METHOD(reload:(nonnull NSNumber *)reactTag)
{
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view = viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWKWebView, got: %@", view);
        } else {
            YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView reload];
        }
    }];
}

RCT_EXPORT_METHOD(sendToBridge:(nonnull NSNumber *)reactTag
                  value:(NSString *)value)
{
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view = viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
        } else {
             YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView sendToBridge:value];
        }
    }];
}

RCT_EXPORT_METHOD(sendObjectToBridge:(nonnull NSNumber *)reactTag
                  value:(id)value)
{
    // @"-[RCTUIManager addUIBlock:] should only be called from the "
    // "UIManager's queue (get this using `RCTGetUIManagerQueue()`)"
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view = viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
        } else {
            YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView sendToBridge:value];
        }
    }];
}

RCT_EXPORT_METHOD(evaluateScript:(nonnull NSNumber *)reactTag script:(NSString *)script resolver:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject)
{
    [self.bridge.uiManager addUIBlock:^(__unused RCTUIManager *uiManager, NSDictionary<NSNumber *, RCTView *> *viewRegistry) {
        RCTView *view = viewRegistry[reactTag];
        if (![view isKindOfClass:[YuanXinWebView class]]) {
            RCTLogError(@"Invalid view returned from registry, expecting RCTWebViewBridge, got: %@", view);
        } else {
            YuanXinWebView *webView  = (YuanXinWebView *)view;
            [webView evaluateScript:script resolver:resolve rejecter:reject];
        }
    }];
}


#pragma mark - Exported synchronous methods

- (BOOL)webView:(__unused YuanXinWebView *)webView
shouldStartLoadForRequest:(NSMutableDictionary<NSString *, id> *)request
   withCallback:(RCTDirectEventBlock)callback
{
    _shouldStartLoadLock = [[NSConditionLock alloc] initWithCondition:arc4random()];
    _shouldStartLoad = YES;
    request[@"lockIdentifier"] = @(_shouldStartLoadLock.condition);
    callback(request);

    // Block the main thread for a maximum of 250ms until the JS thread returns
    if ([_shouldStartLoadLock lockWhenCondition:0 beforeDate:[NSDate dateWithTimeIntervalSinceNow:.25]]) {
        BOOL returnValue = _shouldStartLoad;
        [_shouldStartLoadLock unlock];
        _shouldStartLoadLock = nil;
        return returnValue;
    } else {
        RCTLogWarn(@"Did not receive response to shouldStartLoad in time, defaulting to YES");
        return YES;
    }
}

RCT_EXPORT_METHOD(startLoadWithResult:(BOOL)result lockIdentifier:(NSInteger)lockIdentifier)
{
    if ([_shouldStartLoadLock tryLockWhenCondition:lockIdentifier]) {
        _shouldStartLoad = result;
        [_shouldStartLoadLock unlockWithCondition:0];
    } else {
        RCTLogWarn(@"startLoadWithResult invoked with invalid lockIdentifier: "
                   "got %ld, expected %ld", (long)lockIdentifier, (long)_shouldStartLoadLock.condition);
    }
}

RCT_EXPORT_METHOD(storeCachedResponseForUrlObject:(id)urlObject) {
    NSArray *urlObjectArray = nil;
    if(urlObject) {
        if ([urlObject isKindOfClass:[NSDictionary class]]) {
            urlObjectArray = [NSArray arrayWithObject:urlObject];
        } else if ([urlObject isKindOfClass:[NSArray class]]) {
            urlObjectArray = urlObject;
        }
    }
    for (NSDictionary *_urlObject in urlObjectArray) {
        //
        if ([_urlObject isKindOfClass:[NSDictionary class]]) {
            NSString *urlStr = [RCTConvert NSString:_urlObject[@"url"]];
            NSData *data = _urlObject[@"data"];
            if ([urlStr isKindOfClass:[NSString class]]) {
                if (![data isKindOfClass:[NSData class]]) {
                    if ([data isKindOfClass:[NSDictionary class]]) {
                        NSString *uri = [(NSDictionary *)data objectForKey:@"uri"];
                        if (uri) {
                            data = [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:uri ofType:nil]];
                        }
                    } else if ([data isKindOfClass:[NSString class]]) {
                        data = [(NSString *)data dataUsingEncoding:NSUTF8StringEncoding];
                    } else {
                        break;
                    }
                }
                if ([data isKindOfClass:[NSData class]] && data.length > 0) {
                    [[JWUrlCacheConfig instance] storeCachedResponseForUrl:[NSURL URLWithString:urlStr] data:data];
                }
            }
        }
    }
}

RCT_EXPORT_METHOD(removeCachedResponseForUrl:(id)urlStr) {
    NSArray *urlStrArray = nil;
    if(urlStr) {
        if ([urlStr isKindOfClass:[NSString class]]) {
            urlStrArray = [NSArray arrayWithObject:urlStr];
        } else if ([urlStr isKindOfClass:[NSArray class]]) {
            urlStrArray = urlStr;
        }
    }
    for (NSString *_urlStr in urlStrArray) {
        //
        if ([_urlStr isKindOfClass:[NSString class]]) {
            [[JWUrlCacheConfig instance] removeCachedResponseForUrl:[NSURL URLWithString:urlStr]];
        }
    }
}

RCT_EXPORT_METHOD(removeAllCachedResponse) {
    [[JWUrlCacheConfig instance] removeAllCachedResponse];
}

@end
